﻿Function New-ComputerServiceDiscovery($neo4jServerName,$neo4jUserName,$neo4jPassword)
{
    Import-Module -Force ..\ActiveDirectory\libActiveDirectory.psm1
    

    $computers=(Get-ADComputer -Filter {(name -notlike "*v-*") -and (OperatingSystem -like "*Server*")})

    foreach($computer in $computers)
    {
        New-ComputerServiceGraph -computerName $computer.Name -neo4jServerName $neo4jServerName -neo4jUserName $neo4jUserName -neo4jPassword $neo4jPassword
    }
}

Function New-ComputerServiceGraph($computerName,$neo4jServerName,$neo4jUserName,$neo4jPassword)
{
    Import-Module -Force ..\Neo4j\libNeo4j.psm1

    $computerNodeQuery="MATCH (computer) WHERE computer.name = '$computerName' RETURN computer,id(computer)"

    $computerNode=Get-Neo4jCypherQueryResult -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -cypherQuery $computerNodeQuery

    if($computerNode.results[0].data.Count -eq 0)
    {
        $computerNode=New-Neo4jNode -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -properties @{name=$computerName;}
        Set-Neo4jNodeLabel -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -nodeId $computerNode.metadata.id -labels @("Server")
        $computerNodeId=$computerNode.metadata.id    
    }
    else
    {
        $computerNodeId=$computerNode.results[0].data[0].row[1];
    }
    

    $connectionTest=Test-Connection -Count 1 -ComputerName $computerName -ErrorAction SilentlyContinue
    if($connectionTest)
    {

        $computerServices=Get-Service -ComputerName $computerName | Select-Object Name,Status

        foreach($computerService in $computerServices)
        {
            $serviceNodeQuery="MATCH ((computer:Server)--(service:SQLServerInstance)) WHERE computer.name = '$computerName' AND service.name = '"+$computerService.Name+"' RETURN service,id(service)"

            $serviceNode=Get-Neo4jCypherQueryResult -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -cypherQuery $serviceNodeQuery

            if($serviceNode.results[0].data.Count -eq 0)
            {
                $serviceNode=New-Neo4jNode -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -properties @{name=$computerService.Name;status=$computerService.Status}
                $message="Node for " + $computerService.Name + " for " + $computerName + " created"
                Write-Output $message
                
                Set-Neo4jNodeLabel -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -nodeId $serviceNode.metadata.id -labels @("Service")


                if($computerService.Name -eq "W3SVC")
                {
                    Set-Neo4jNodeLabel -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -nodeId $serviceNode.metadata.id -labels @("WebServer")    
                }
                $serviceNodeId=$serviceNode.metadata.id    
            }
            else
            {
                $serviceNodeId=$serviceNode.results[0].data[0].row[1];
            }

            $relationship=New-Neo4jRelationship -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -sourceNodeId $computerNodeId -targetNodeId $serviceNodeId -type "SERVES"
            $message="Relationship for " + $computerService.Name + " for " + $computerName + " created"
            Write-Output $message
        }
    }

}

Function New-ActiveDirectoryGraph($neo4jServerName,$neo4jUserName,$neo4jPassword)
{
    Import-Module -Force ..\ActiveDirectory\libActiveDirectory.psm1
    Import-Module -Force ..\Neo4j\libNeo4j.psm1

    $domain=Get-ADDomain

    $domainNodeQuery="MATCH (domain:ActiveDirectoryDomain) WHERE domain.name = '"+$domain.NetBIOSName+"' RETURN domain,id(domain)"

    $domainNode=Get-Neo4jCypherQueryResult -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -cypherQuery $domainNodeQuery
    
    if($domainNode.results[0].data.Count -eq 0)
    {
        $domainNode=New-Neo4jNode -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -properties @{name=$domain.NetBIOSName;}
        Set-Neo4jNodeLabel -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -nodeId $domainNode.metadata.id -labels @("ActiveDirectoryDomain")
        $domainNodeId=$domainNode.metadata.id    
    }
    else
    {
        $domainNodeId=$domainNode.results[0].data[0].row[1];
    }


    $computers=(Get-ADComputer -Filter {(name -notlike "*v-*") -and (OperatingSystem -like "*Server*")})



    foreach($computer in $computers)
    {
        $computerNodeQuery="MATCH (computer:Server) WHERE computer.name = '"+ $computer.Name + "' RETURN computer,id(computer)"

        $computerNode=Get-Neo4jCypherQueryResult -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -cypherQuery $computerNodeQuery
    
        if($computerNode.results[0].data.Count -eq 0)
        {
            $computerNode=New-Neo4jNode -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -properties @{name=$computer.Name;}
            Set-Neo4jNodeLabel -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -nodeId $computerNode.metadata.id -labels @("Server")
            $computerNodeId=$computerNode.metadata.id    
        }
        else
        {
            $computerNodeId=$computerNode.results[0].data[0].row[1];
        }   

        New-Neo4jRelationship -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -sourceNodeId $computerNodeId -targetNodeId $domainNodeId -type "IS_MEMBER_OF"
    }

}

Function New-SQLServerDiscovery($neo4jServerName,$neo4jUserName,$neo4jPassword)
{
    Import-Module -Force ..\Neo4j\libNeo4j.psm1

    $sqlServerQuery="match ((server:Server)--(service:Service)) WHERE service.name ='MSSQLSERVER' and service.status='Running' return server.name"

    $sqlServerNodes=Get-Neo4jCypherQueryResult -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -cypherQuery $sqlServerQuery

    foreach($sqlServerNode in $sqlServerNodes.results[0].data)
    {
        New-SQLServerGraph -sqlServerName $sqlServerNode.row -neo4jServerName $neo4jServerName -neo4jUserName $neo4jUserName -neo4jPassword $neo4jPassword
    }
}

Function New-SQLServerGraph($sqlServerName,$sqlUserName,$sqlPassword,$neo4jServerName,$neo4jUserName,$neo4jPassword)
{
    Import-Module -Force ..\Neo4j\libNeo4j.psm1
    Import-Module -Force ..\SQLServer\libSQLServerStatistics.psm1

    $computerNodeQuery="MATCH (computer:Server) WHERE computer.name = '$sqlServerName' RETURN computer,id(computer)"

    $computerNode=Get-Neo4jCypherQueryResult -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -cypherQuery $computerNodeQuery
    
    if($computerNode.results[0].data.Count -eq 0)
    {
        $computerNode=New-Neo4jNode -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -properties @{name=$sqlServerName;}
        Set-Neo4jNodeLabel -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -nodeId $computerNode.metadata.id -labels @("Server")
        $computerNodeId=$computerNode.metadata.id    
    }
    else
    {
        $computerNodeId=$computerNode.results[0].data[0].row[1];
    }
    
    $serviceNodeQuery="MATCH ((computer:Server)--(service:SQLServerInstance)) WHERE computer.name = '$sqlServerName' AND service.name = '$sqlServerName' RETURN service,id(service)"

    $serviceNode=Get-Neo4jCypherQueryResult -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -cypherQuery $serviceNodeQuery

    if($serviceNode.results[0].data.Count -eq 0)
    {
        $serviceNode=New-Neo4jNode -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -properties @{name=$sqlServerName;}
        Set-Neo4jNodeLabel -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -nodeId $serviceNode.metadata.id -labels @("SQLServerInstance")
        $serviceNodeId=$serviceNode.metadata.id    
    }
    else
    {
        $serviceNodeId=$serviceNode.results[0].data[0].row[1];
    }

    New-Neo4jRelationship -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -sourceNodeId $computerNodeId -targetNodeId $serviceNodeId -type "SERVES"

    if($sqlUserName -ne $null -and $sqlPassword -ne $null)
    {
        $databases=Get-SQLDatabaseName -serverName $sqlServerName -userName $sqlUserName -password $sqlPassword -excludeSystemDatabases
    }
    else
    {
        $databases=Get-SQLDatabaseName -serverName $sqlServerName -excludeSystemDatabases
    }
    foreach($database in $databases)
    {
        $databaseNodeQuery="MATCH ((computer:Server)--(service:SQLServerInstance)--(database:Database)) WHERE computer.name = '$sqlServerName' AND database.name = '$database' RETURN database,id(database)"
        
        $databaseNode=Get-Neo4jCypherQueryResult -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -cypherQuery $databaseNodeQuery

        if($databaseNode.results[0].data.Count -eq 0)
        {
            $databaseNode=New-Neo4jNode -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -properties @{name=$database;}
            Set-Neo4jNodeLabel -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -nodeId $databaseNode.metadata.id -labels @("Database")
            $databaseNodeId=$databaseNode.metadata.id
              
        }
        else
        {
            $databaseNodeId=$databaseNode.results[0].data[0].row[1]; 
        }

        New-Neo4jRelationship -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -sourceNodeId $serviceNodeId -targetNodeId $databaseNodeId -type "SERVES"
    }
}

Function New-WebServerDiscovery($neo4jServerName,$neo4jUserName,$neo4jPassword,$credential)
{
    Import-Module -Force ..\Neo4j\libNeo4j.psm1

    $servicesQuery="match ((server:Server)--(service:Service)) WHERE service.name ='W3SVC' and service.status='Running' return server.name"

    $servicesNodes=Get-Neo4jCypherQueryResult -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -cypherQuery $servicesQuery

    foreach($servicesNode in $servicesNodes.results[0].data)
    {
        New-WebServerGraph -iisServerName $servicesNode.row -neo4jServerName $neo4jServerName -neo4jUserName $neo4jUserName -neo4jPassword $neo4jPassword -credential $credential
    }   
}

<#
.DESCRIPTION
    Discovers web sites running in IIS on a computer and populates the graph accordingly.
.PARAMETER iisServerName
    The name of the computer for which to perform the program discovery.
.PARAMETER neo4jServerName
    The name of the Neo4j server.
.PARAMETER neo4jUserName
    The user to use to connect to Neo4j.
.PARAMETER neo4jPassword
    The password to user to connect to Neo4j.
.PARAMETER credential
    The credentials to use to authenticate to the IIS server.    
#>
Function New-WebServerGraph($iisServerName,$neo4jServerName,$neo4jUserName,$neo4jPassword,$credential)
{
    Import-Module -Force ..\BuildDeployment\libUtilities.psm1
    Import-Module -Force ..\Neo4j\libNeo4j.psm1

    $computerNodeQuery="MATCH (computer:Server) WHERE computer.name = '$iisServerName' RETURN computer,id(computer)"

    $computerNode=Get-Neo4jCypherQueryResult -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -cypherQuery $computerNodeQuery
    
    if($computerNode.results[0].data.Count -eq 0)
    {
        $computerNode=New-Neo4jNode -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -properties @{name=$iisServerName;}
        Set-Neo4jNodeLabel -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -nodeId $computerNode.metadata.id -labels @("Server")
        $computerNodeId=$computerNode.metadata.id    
    }
    else
    {
        $computerNodeId=$computerNode.results[0].data[0].row[1];
    }
    
    $serviceNodeQuery="MATCH ((computer:Server)--(service:WebServer)) WHERE computer.name = '$iisServerName' AND service.name = 'W3SVC' RETURN service,id(service)"

    $serviceNode=Get-Neo4jCypherQueryResult -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -cypherQuery $serviceNodeQuery

    if($serviceNode.results[0].data.Count -eq 0)
    {
        $serviceNode=New-Neo4jNode -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -properties @{name='W3SVC';}
        Set-Neo4jNodeLabel -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -nodeId $serviceNode.metadata.id -labels @("WebServer")
        $serviceNodeId=$serviceNode.metadata.id    
    }
    else
    {
        $serviceNodeId=$serviceNode.results[0].data[0].row[1];
    }

    New-Neo4jRelationship -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -sourceNodeId $computerNodeId -targetNodeId $serviceNodeId -type "SERVES"

    #$session=Assert-PSSession -computerAddress $iisServerName -useCredSSP -credential $credential

    #$webSites=Invoke-Command -Session $session -ScriptBlock {Get-Website | Select Name}

    $webSites=Get-WmiObject -ComputerName $iisServerName -Namespace "root/MicrosoftIISv2" -Class IIsWebServerSetting | Select-Object -Expandproperty ServerComment

    foreach($webSite in $webSites)
    {
        $webSiteNodeQuery="MATCH ((computer:Server)--(service:WebServer)--(webSite:WebSite)) WHERE computer.name = '$iisServerName' AND webSite.name = '"+ $webSite +"' RETURN webSite,id(webSite)"
        
        $webSiteNode=Get-Neo4jCypherQueryResult -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -cypherQuery $webSiteNodeQuery

        if($webSiteNode.results[0].data.Count -eq 0)
        {
            $webSiteNode=New-Neo4jNode -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -properties @{name=$webSite;}
            Set-Neo4jNodeLabel -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -nodeId $webSiteNode.metadata.id -labels @("WebSite")
            $webSiteNodeId=$webSiteNode.metadata.id
              
        }
        else
        {
            $webSiteNodeId=$webSiteNode.results[0].data[0].row[1]; 
        }

        New-Neo4jRelationship -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -sourceNodeId $serviceNodeId -targetNodeId $webSiteNodeId -type "SERVES"
    }

    $applicationPools=Get-WmiObject -ComputerName $iisServerName  -Namespace "root/MicrosoftIISv2" -Class IIsApplicationPoolSetting | SELECT Name,WAMUserName

    foreach($applicationPool in $applicationPools)
    {
        $applicationPoolNodeQuery="MATCH ((computer:Server)--(service:WebServer)--(applicationPool:ApplicationPool)) WHERE computer.name = '$iisServerName' AND applicationPool.name = '"+ $applicationPool.Name +"' RETURN applicationPool,id(applicationPool)"
        
        $applicationPoolNode=Get-Neo4jCypherQueryResult -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -cypherQuery $applicationPoolNodeQuery

        if($applicationPoolNode.results[0].data.Count -eq 0)
        {
            $applicationPoolNode=New-Neo4jNode -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -properties @{name=$applicationPool.Name.Replace("W3SVC/APPPOOLS/","");}
            Set-Neo4jNodeLabel -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -nodeId $applicationPoolNode.metadata.id -labels @("ApplicationPool")
            $applicationPoolNodeId=$applicationPoolNode.metadata.id
              
        }
        else
        {
            $applicationPoolNodeId=$applicationPoolNode.results[0].data[0].row[1]; 
        }

        New-Neo4jRelationship -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -sourceNodeId $serviceNodeId -targetNodeId $applicationPoolNodeId -type "SERVES"



        #Identity
        <#if($applicationPool.WAMUserName -ilike "*\*")
        {
            $identityDomain=$applicationPool.WAMUserName.Split("\")[0]
            $identityUserName=$applicationPool.WAMUserName.Split("\")[1]
            if(
            $applicationPoolIdentityNodeQuery="MATCH ((computer:Server)--(service:WebServer)--(applicationPool:ApplicationPool)) WHERE computer.name = '$iisServerName' AND applicationPool.name = '"+ $applicationPool.Name +"' RETURN applicationPool,id(applicationPool)"
        
            $applicationPoolIdentityNode=Get-Neo4jCypherQueryResult -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -cypherQuery $applicationPoolNodeQuery

            if($applicationPoolIdentityNode.results[0].data.Count -eq 0)
            {
                $applicationPoolIdentityNode=New-Neo4jNode -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -properties @{name=$applicationPool.WAMUserName;}
                Set-Neo4jNodeLabel -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -nodeId $applicationPoolIdentityNode.metadata.id -labels @("ActiveDirectoryUser")
                $applicationPoolIdentityNodeId=$applicationPoolIdentityNode.metadata.id
              
            }
            else
            {
                $applicationPoolNodeId=$applicationPoolNode.results[0].data[0].row[1]; 
            }

            New-Neo4jRelationship -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -sourceNodeId $serviceNodeId -targetNodeId $applicationPoolNodeId -type "SERVES"
        }
        #>
    }
}

<#
.DESCRIPTION
    Discovers installed programs on a computer and populates the graph accordingly.
.PARAMETER computerName
    The name of the computer for which to perform the program discovery.
.PARAMETER neo4jServerName
    The name of the Neo4j server.
.PARAMETER neo4jUserName
    The user to use to connect to Neo4j.
.PARAMETER neo4jPassword
    The password to user to connect to Neo4j.    
#>
Function New-ComputerProgramGraph($computerName,$neo4jServerName,$neo4jUserName,$neo4jPassword)
{
    Import-Module -Force ..\Neo4j\libNeo4j.psm1

    $computerNodeQuery="MATCH (computer) WHERE computer.name = '$computerName' RETURN computer,id(computer)"

    $computerNode=Get-Neo4jCypherQueryResult -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -cypherQuery $computerNodeQuery

    if($computerNode.results[0].data.Count -eq 0)
    {
        $computerNode=New-Neo4jNode -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -properties @{name=$computerName;}
        Set-Neo4jNodeLabel -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -nodeId $computerNode.metadata.id -labels @("Server")
        $computerNodeId=$computerNode.metadata.id    
    }
    else
    {
        $computerNodeId=$computerNode.results[0].data[0].row[1];
    }
    

    $connectionTest=Test-Connection -Count 1 -ComputerName $computerName -ErrorAction SilentlyContinue
    if($connectionTest)
    {

        $computerProrams=Get-WmiObject -Class Win32_Product -ComputerName $computerName | Select-Object Name,Vendor,Version,Caption

        foreach($computerProgram in $computerPrograms)
        {
            $programNodeQuery="MATCH ((computer:Server)--(program:Program)) WHERE computer.name = '$computerName' AND program.name = '"+$computerProgram.Name+"' RETURN program,id(program)"

            $programNode=Get-Neo4jCypherQueryResult -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -cypherQuery $serviceNodeQuery

            if($programNode.results[0].data.Count -eq 0)
            {
                $programNode=New-Neo4jNode -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -properties @{name=$computerProgram.Name;vendor=$computerProgram.Vendor;version=$computerProgram.Version;caption=$computerProgram.Caption}
                $message="Node for " + $computerProgram.Name + " for " + $computerName + " created"
                Write-Output $message
                
                Set-Neo4jNodeLabel -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -nodeId $serviceNode.metadata.id -labels @("Program")


                
                $programNodeId=$programNode.metadata.id    
            }
            else
            {
                $programNodeId=$programNode.results[0].data[0].row[1];
            }

            $relationship=New-Neo4jRelationship -serverName $neo4jServerName -userName $neo4jUserName -password $neo4jPassword -sourceNodeId $computerNodeId -targetNodeId $programNodeId -type "HAS"
            $message="Relationship for " + $computerProgram.Name + " for " + $computerName + " created"
            Write-Output $message
        }
    }

}
